package com.winit.common.sg;

import com.alibaba.fastjson.JSONObject;
import com.sun.source.tree.*;
import com.sun.source.util.JavacTask;
import com.sun.source.util.TreeScanner;
import com.sun.tools.javac.api.JavacTool;
import com.sun.tools.javac.file.JavacFileManager;
import com.sun.tools.javac.parser.Parser;
import com.sun.tools.javac.parser.ParserFactory;
import com.sun.tools.javac.tree.JCTree.JCCompilationUnit;
import com.sun.tools.javac.util.Context;

import javax.tools.JavaCompiler;
import javax.tools.JavaFileObject;
import java.io.FileInputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.FileChannel.MapMode;
import java.nio.charset.Charset;
import java.util.*;

/**
 * @author wanglin
 */
public class JavaParserUtil {
    private ParserFactory factory;

    private JavacFileManager manager;
    private JavacTool javacTool;

    public JavaParserUtil() {
        factory = getParserFactory();

        Context context = new Context();
        manager = new JavacFileManager(context, true, Charset.defaultCharset());
        javacTool = new JavacTool();
    }

    public List<JSONObject> parseMethodDefs(String file) throws IOException {
        JCCompilationUnit unit = parse(file);
        MethodScanner scanner = new MethodScanner();
        return scanner.visitCompilationUnit(unit, new ArrayList<JSONObject>());

    }

    JCCompilationUnit parse(String file) throws IOException {
        Parser parser = factory.newParser(readFile(file), true, false, true);
        return parser.parseCompilationUnit();
    }

    private ParserFactory getParserFactory() {
        Context context = new Context();
        JavacFileManager.preRegister(context);
        ParserFactory factory = ParserFactory.instance(context);
        return factory;
    }

    CharSequence readFile(String file) throws IOException {
        FileInputStream fin = new FileInputStream(file);
        FileChannel ch = fin.getChannel();
        ByteBuffer buffer = ch.map(MapMode.READ_ONLY, 0, ch.size());
        return Charset.defaultCharset().decode(buffer);
    }

    //扫描方法时，把方法名加入到一个list中
    static class MethodScanner extends
            TreeScanner<List<JSONObject>, List<JSONObject>> {
        @Override
        public List<JSONObject> visitMethod(MethodTree node, List<JSONObject> p) {
            JSONObject json=new JSONObject();
            json.put("name",node.getName().toString());
            if(node.getTypeParameters().size()!=0){
                json.put("rtnExtends",node.getTypeParameters().get(0).getBounds().toString());
            }

            json.put("rtn",node.getReturnType().toString());
            List<JSONObject> params = new ArrayList<>();
            for(VariableTree sda :node.getParameters()){
                JSONObject param = new JSONObject();
                param.put("type",sda.getType().toString());
                param.put("name",sda.getName().toString());
                params.add(param);
            }
            json.put("params", params);
            p.add(json);

            return p;
        }
    }


    public void parseJavaFiles(String path) {
        Iterable<? extends JavaFileObject> files = manager.getJavaFileObjects(path);
        JavaCompiler.CompilationTask compilationTask = javacTool.getTask(null, manager, null, null, null, files);
        JavacTask javacTask = (JavacTask) compilationTask;
        try {
            Iterable<? extends CompilationUnitTree> result = javacTask.parse();
            for (CompilationUnitTree tree:result){
                tree.accept(new SourceVisitor(), null);
            }
        }catch (Exception e){
            e.printStackTrace();
        }
    }
    public static Set<JSONObject> set;
    static class  SourceVisitor extends TreeScanner<Void,Void> {
        private String currentPackageName = null;

        @Override
        public Void visitClass(ClassTree node, Void aVoid) {
            for(Tree member:node.getMembers()){
                if("VARIABLE".equalsIgnoreCase(String.valueOf(member.getKind()))){
                    JSONObject map = new JSONObject();
                    map.put("type",((VariableTree) member).getType());
                    map.put("name",String.valueOf(((VariableTree) member).getName()));
                    set.add(map);
//                    formatPtrln("variable name: %s, type: %s", ((VariableTree) member).getName(), ((VariableTree) member).getType());
                }
            }
            return null;
        }

//        @Override
//        public Void visitVariable(VariableTree node, Void aVoid) {
//            formatPtrln("variable name: %s, type: %s, kind: %s, package: %s", node.getName(), node.getType(), node.getKind(), currentPackageName);
//            return null;
//        }
    }

    public static  void  formatPtrln(String format, Object... args) {
        System.out.println(String.format(format, args));
    }


    public static Set<JSONObject> getParameter(String path,Set<JSONObject> oldSet){
        set=oldSet;
        new JavaParserUtil().parseJavaFiles(path);
        return set;
    }





    public static void main(String[] args) throws IOException {
        set=new HashSet<>();
        for (JSONObject method : new JavaParserUtil().parseMethodDefs("/Users/wanglin/JavaProject/spi/src/main/java/com/winit/cwm/spi/csi/ScanOperationService.java")) {
            System.out.println(method);
        }
    }

}
